package com.ylp.sys.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylp.common.exception.ServiceException;
import com.ylp.common.utils.StringUtils;
import com.ylp.sys.auth.entity.UserInfo;
import com.ylp.sys.domain.entity.SysMenu;
import com.ylp.sys.domain.entity.SysRole;
import com.ylp.sys.domain.entity.SysRoleMenu;
import com.ylp.sys.domain.vo.MenuVo;
import com.ylp.sys.domain.vo.RouterVO;
import com.ylp.sys.mapper.SysMenuMapper;
import com.ylp.sys.mapper.SysRoleMapper;
import com.ylp.sys.mapper.SysRoleMenuMapper;
import com.ylp.sys.mapper.SysUserRoleMapper;
import com.ylp.sys.service.SysMenuService;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单表 服务实现类
 * </p>
 *
 * @author cc
 * @since 2024-07-24
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    private final SysUserRoleMapper userRoleMapper;
    private final SysRoleMapper roleMapper;
    private final SysRoleMenuMapper roleMenuMapper;
    private final SysMenuMapper menuMapper;

    public SysMenuServiceImpl(SysUserRoleMapper userRoleMapper, SysRoleMapper roleMapper,
                              SysRoleMenuMapper roleMenuMapper, SysMenuMapper menuMapper) {
        this.userRoleMapper = userRoleMapper;
        this.roleMapper = roleMapper;
        this.roleMenuMapper = roleMenuMapper;
        this.menuMapper = menuMapper;
    }

    /**
     * 根据用户id 获取菜单
     * @param id
     * @return
     */
    @Override
    public List<RouterVO> getMenuByUserId(Long id) {
        List<SysMenu> menus = menuMapper.getMenuListByUserId(id);
        //通过递归设置菜单的树形结构
        // 1、获取所有的1级菜单【parentId=0】
        // 2、遍历1级菜单，获取他所有的子元素【其他数据的parentId=当前元素的id】
        List<RouterVO> router = getRourerList(menus);
        return router;
    }

    /**
     * 获取路由
     * @param menus
     * @return
     */
    private List<RouterVO> getRourerList(List<SysMenu> menus) {
        List<RouterVO> routerVOS = new ArrayList<>();
        // 获取所有一级路由
        List<SysMenu> parentMenu = menus.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());
        // 转换类型对象
        for (SysMenu menu: parentMenu) {
            RouterVO routerVO = new RouterVO();
            BeanUtil.copyProperties(menu, routerVO);
            routerVOS.add(routerVO);
        }
        // 循环1级路由, 获取子菜单
        for (RouterVO routerVO: routerVOS) {
            // 获取所有子节点
            List<RouterVO> childList = buildTree(menus, routerVO.getId());
            routerVO.setChildren(childList);
        }
        return routerVOS;
    }

    /**
     * 递归匹配所有的子节点
     * @param menus
     * @param parentId
     * @return
     */
    private List<RouterVO> buildTree(List<SysMenu> menus, Long parentId) {
        List<RouterVO> childList = new ArrayList<>();
        for (SysMenu menu: menus) {
            // 判断menu parentId 是否等于传入parentId
            if (menu.getParentId().equals(parentId)) {
                RouterVO routerVO = new RouterVO();
                BeanUtil.copyProperties(menu, routerVO);
                childList.add(routerVO);
            }
        }
        // 递归childList 可能还存在的子节点
        for (RouterVO childItem: childList) {
            childItem.setChildren(buildTree(menus, childItem.getId()));
        }
        return childList;
    }

    /**
     * 查询菜单树
     * @return
     */
    @Override
    public List<Map<String, Object>> treeselect() {
        List<Map<String, Object>> menuTree = new ArrayList<>();
        try {
            // 查询所有菜单
            List<SysMenu> menus = menuMapper.selectList(null);
            // 获取所有一级
            List<SysMenu> parentMenu = menus.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());
            // 转换类型对象
            for (SysMenu menu: parentMenu) {
                Map<String, Object> map = new HashMap<>();
                map.put("value", menu.getId());
                map.put("label", menu.getMenuName());
                menuTree.add(map);
            }
            // 循环1级路由, 获取子菜单
            for (int i = 0; i < menuTree.size(); i++) {
                // 获取所有子节点
                List<Map<String, Object>> childList = childTree(menus, (Long) menuTree.get(i).get("value"));
                menuTree.get(i).put("children", childList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException();
        }
        return menuTree;
    }

    /**
     * 获取菜单树表格
     * @param menu
     * @return
     */
    @Override
    public List<MenuVo> getListTree(SysMenu menu) {
        List<MenuVo> menuVos = new ArrayList<>();
        try {
            // 1 按条件查询
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.like(StringUtils.isNotEmpty(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName())
                    .like(ObjectUtil.isNotNull(menu.getStatus()), SysMenu::getStatus, menu.getStatus());
            wrapper.orderByAsc(SysMenu::getSort);
            List<SysMenu> menus = menuMapper.selectList(wrapper);
            if (menus.isEmpty()) {
                return menuVos;
            }
            // 获取所有一级
            List<SysMenu> parentMenu = menus.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());
            if (!menus.isEmpty() && parentMenu.isEmpty()) {
                SysMenu menu1 =  menus.get(0);
                for (SysMenu menu2: menus) {
                    if (menu1.getParentId() > menu2.getParentId()) {
                        menu1 = menu2;
                    }
                }
                // 判断父id 是否有
                Long paId = menu1.getParentId();
                List<Long> parId = menus.stream().filter(item -> item.getId() == paId).map(SysMenu::getId).collect(Collectors.toList());
                if (parId.isEmpty()) {
                    for (SysMenu me: menus) {
                        MenuVo menuVo = new MenuVo();
                        BeanUtil.copyProperties(me, menuVo);
                        menuVos.add(menuVo);
                    }
                    return menuVos;
                }
                parentMenu = new ArrayList<>();
                parentMenu.add(menu1);
            }
            // 转换类型对象
            for (SysMenu menuPa: parentMenu) {
                MenuVo menuVo = new MenuVo();
                BeanUtil.copyProperties(menuPa, menuVo);
                menuVos.add(menuVo);
            }
            // 2 组织树结构
            // 循环1级路由, 获取子菜单
            for (MenuVo menuVo: menuVos) {
                // 获取所有子节点
                List<MenuVo> childList = childTableTree(menus, menuVo.getId());
                menuVo.setChildren(childList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("查询失败");
        }
        return menuVos;
    }

    @Override
    public void addMenu(SysMenu menu) {
        UserInfo userLoginInfo = (UserInfo) StpUtil.getSession().get("userInfo");
        String userName = userLoginInfo.getUsername();
        menu.setCreator(userName);
        menu.setUpdater(userName);
        menu.setDeleted(0);
        menuMapper.insert(menu);
    }

    /**
     * 修改
     * @param menu
     */
    @Override
    public void editMenu(SysMenu menu) {
        UserInfo userLoginInfo = (UserInfo) StpUtil.getSession().get("userInfo");
        String userName = userLoginInfo.getUsername();
        menu.setUpdater(userName);
        menuMapper.updateById(menu);
    }

    @Override
    public SysMenu getMenuById(Long id) {
        SysMenu menu = null;
        try {
            menu = menuMapper.selectById(id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("查询失败");
        }
        return menu;
    }

    /**
     * 删除
     * @param id
     */
    @Override
    public void deleteMenuCheckChildAndRole(Long id) {
        // 1.检查是否被引用
        if (ObjectUtil.isNotNull(id)) {
//                LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
//                wrapper.eq(SysRoleMenu::getMenuId, id);
//                Long count = roleMenuMapper.selectCount(wrapper);
//                if (count > 0) {
//                    throw new ServiceException("该菜单被引用，请先取消角色的关联");
//                }
            try {
                //获取所有菜单
                List<SysMenu> menus = menuMapper.selectList(null);
                List<RouterVO> routerVOS = buildTree(menus, id);
                List<Long> ids = routerVOS.stream().map(RouterVO::getId).collect(Collectors.toList());
                ids.add(id);
                // 检查菜单是否被引用
                for (Long childId: ids) {
                    LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(SysRoleMenu::getMenuId, childId);
                    Long count = roleMenuMapper.selectCount(wrapper);
                    if (count > 0) {
                        throw new ServiceException("该菜单被引用，请先取消角色的关联");
                    }
                }
                menuMapper.deleteBatchIds(ids);
            } catch (ServiceException s) {
                s.printStackTrace();
                throw s;
            } catch (Exception e) {
                e.printStackTrace();
                throw new ServiceException("删除失败");
            }
        } else {
            throw new ServiceException("id不能为空");
        }
    }

    //构建表格树
    private List<MenuVo> childTableTree(List<SysMenu> menus, Long parentId) {
        List<MenuVo> menuVos = new ArrayList<>();
        for (SysMenu menu: menus) {
            // 判断menu parentId 是否等于传入parentId
            if (menu.getParentId().equals(parentId)) {
                MenuVo menuVo = new MenuVo();
                BeanUtil.copyProperties(menu, menuVo);
                menuVos.add(menuVo);
            }
        }
        // 递归childList 可能还存在的子节点
        for (MenuVo menuVo: menuVos) {
            menuVo.setChildren(childTableTree(menus, menuVo.getId()));
        }
        return menuVos;
    }

    /**
     * 构建菜单树
     * @param menus
     */
    public List<MenuVo> buileMenuTree(List<SysMenu> menus) {
        List<MenuVo> menuVos = new ArrayList<>();
        // 遍历一级菜单
        // 获取所有一级
        List<SysMenu> parentMenu = menus.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());
        // 转换类型对象
        for (SysMenu menuPa: parentMenu) {
            MenuVo menuVo = new MenuVo();
            BeanUtil.copyProperties(menuPa, menuVo);
            menuVos.add(menuVo);
        }
        // 2 组织树结构
        // 循环1级路由, 获取子菜单
        for (MenuVo menuVo: menuVos) {
            // 获取所有子节点
            List<MenuVo> childList = childTableTree(menus, menuVo.getId());
            menuVo.setChildren(childList);
        }
        return menuVos;
    }

    /**
     * 递归匹配所有的子节点
     * @param menus
     * @param parentId
     * @return
     */
    private List<Map<String, Object>> childTree(List<SysMenu> menus, Long parentId) {
        List<Map<String, Object>> childList = new ArrayList<>();
        for (SysMenu menu: menus) {
            // 判断menu parentId 是否等于传入parentId
            if (menu.getParentId().equals(parentId)) {
                Map<String, Object> map = new HashMap<>();
                map.put("value", menu.getId());
                map.put("label", menu.getMenuName());
                childList.add(map);
            }
        }
        // 递归childList 可能还存在的子节点
        for (int i = 0; i < childList.size(); i++) {
            childList.get(i).put("children", childTree(menus, (Long) childList.get(i).get("value")));
        }
        return childList;
    }


    /**
     * 根据用户id 查用户角色中间信息
     * @param userId
     * @return
     */
//    public List<SysUserRole> getUserRoleListByUserId(Long userId) {
//        LambdaQueryWrapper<SysUserRole> wrapper = new LambdaQueryWrapper<>();
//        wrapper.eq(SysUserRole::getUserId, userId);
//        return userRoleMapper.selectList(wrapper);
//    }

    /**
     * 根据角色ids 查角色
     * @param roleIds
     * @return
     */
    public List<SysRole> getRolesByIds(List<Long> roleIds) {
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysRole::getId, roleIds);
        return roleMapper.selectList(wrapper);
    }

    /**
     * 根据角色ids 查菜单角色中间信息
     * @param roleIds
     * @return
     */
//    public List<SysRoleMenu> getRoleMenuListByRoleIds(List<Long> roleIds) {
//        LambdaQueryWrapper<SysRoleMenu> wrapper = new LambdaQueryWrapper<>();
//        wrapper.in(SysRoleMenu::getRoleId, roleIds);
//        return roleMenuMapper.selectList(wrapper);
//    }

    /**
     * 根据菜单ids 查菜单
     * @param menuIds
     * @return
     */
    public List<SysMenu> getMenuListByIds(List<Long> menuIds) {
        LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysMenu::getStatus, 0);
        wrapper.in(SysMenu::getId, menuIds);
        wrapper.orderByAsc(SysMenu::getSort);
        return menuMapper.selectList(wrapper);
    }

    /**
     * 根据id 查 menus
     * @param ids
     * @return
     */
    public List<SysMenu> getListByIds(List<Long> ids) {
        List<SysMenu> menus = new ArrayList<>();
        try {
            menus = menuMapper.selectBatchIds(ids);
        } catch (Exception e) {
            return menus;
        }
        return menus;
    }

    /**
     * id 不在ids中菜单
     * @param ids
     * @return
     */
    public List<SysMenu> getListNotIds(List<Long> ids) {
        List<SysMenu> menus = new ArrayList<>();
        try {
            LambdaQueryWrapper<SysMenu> wrapper = new LambdaQueryWrapper<>();
            wrapper.notIn(SysMenu::getId, ids);
            menus = menuMapper.selectList(wrapper);
        } catch (Exception e) {
            return menus;
        }
        return menus;
    }

}
